package me.sdevil507.supports.shiro.realm;

import me.sdevil507.org.po.OrgUserPo;
import me.sdevil507.org.service.OrgRoleService;
import me.sdevil507.org.service.OrgUserService;
import me.sdevil507.supports.shiro.enums.LoginChannel;
import me.sdevil507.supports.shiro.enums.LoginModeType;
import me.sdevil507.supports.shiro.enums.RoleType;
import me.sdevil507.supports.shiro.realms.BaseAuthorizingRealm;
import me.sdevil507.supports.shiro.token.JWTToken;
import me.sdevil507.supports.util.JwtUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class JwtRealm extends BaseAuthorizingRealm {

    @Autowired
    private OrgRoleService orgRoleService;

    @Autowired
    private OrgUserService orgUserService;

    @Autowired
    RedisTemplate redisTemplate;


    /**
     * 定义realm名称
     *
     * @return realm名称
     */
    @Override
    public String getName() {
        return LoginChannel.WXAPPLET.name() + ":" + LoginModeType.WECHAT.name();
    }

    /**
     * 必须重写此方法，不然会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    /**
     * 获取身份验证信息  通过设置realm的cacheManager，则此方法会被shiro缓存
     * Shiro中，最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     *
     * 这里throw AuthenticationException的话，都会退出session。但这个方法被redis缓存了
     * 如果session缓存到期，则会进入这里重新续费session
     *
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//        System.out.println("————身份认证方法————");
        String phoneNumber = (String) authenticationToken.getCredentials();
//        String loginType = JwtUtil.getLoginType(token);
        //获取用户的输入的账号.
//        String phoneNumber = JwtUtil.getPhoneNumber(token);

        if(StringUtils.isEmpty(phoneNumber))
            throw new AuthenticationException("Token错误");

        OrgUserPo orgUserPo = null;

        try {
            orgUserPo = orgUserService.readOneByPhoneNumber(phoneNumber);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 用户名不存在
        if (orgUserPo == null) {
            throw new UnknownAccountException();
        }

        // 账号被锁定(true:锁定,false:未锁定)
        if (orgUserPo.getLocked()) {
            throw new LockedAccountException();
        }

        /**
         * 只要token不过期，authenticationInfo可以继续刷新
         */
        if(!redisTemplate.hasKey(JwtUtil.JWT_SHIRO_CACHE_KEY_PREFIX  + phoneNumber)){
            throw new AuthenticationException("Token过期");
        }else{
            redisTemplate.expire(JwtUtil.JWT_SHIRO_CACHE_KEY_PREFIX + phoneNumber ,JwtUtil.REDIS_EXPIRE_TIME , TimeUnit.SECONDS);
        }

        // 如果身份认证验证成功，返回一个AuthenticationInfo实现；
        return new SimpleAuthenticationInfo(orgUserPo.getPhoneNumber(),
                "",
                getName()
        );

    }

    /**
     * 获取授权信息，菜单权限
     * 注解RequiresPermissions里面需要
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setStringPermissions(orgRoleService.findPermissions());
        return authorizationInfo;
    }


}

